#ifndef STATE_H
#define STATE_H

#include <vector>
#include <iostream>
#include <string>


#include "evaluationFunction.h"
#include <tr1/functional>

// forward declaration (cyclic dependency)
class Evaluation;


// Possible chess pieces.
enum FieldValue 
{
    BLACK_PAWN, BLACK_KNIGHT, BLACK_BISHOP, BLACK_ROOK, BLACK_QUEEN, BLACK_KING,    
    WHITE_PAWN, WHITE_KNIGHT, WHITE_BISHOP, WHITE_ROOK, WHITE_QUEEN, WHITE_KING,    
    EMPTY  
    // TODO define print?
};

// Possible move types - used especially for 'special moves' like castle or promotion.
enum MoveType 
{
    COMMON,
    LEFTSIDE_CASTLING,
    RIGHTSIDE_CASTLING,
    PROMOTION_FOR_ROOK,
    PROMOTION_FOR_KNIGHT,
    PROMOTION_FOR_BISHOP,
    PROMOTION_FOR_QUEEN,
    ENPASSANT_FIRST_STAGE,  // It means that a pawn is moved by two.
    ENPASSANT_SECOND_STAGE  // That's the beating
};

// Possible colours for player whos move is next.
enum Colour 
{
    WHITE,
    BLACK,
    NONE    
};  

struct Util 
{
    static Colour pieceColour(FieldValue fv);  
    static std::string pieceToString(FieldValue fv);
    static Colour opposite(Colour c);
    static unsigned char*** allocateInfoTable();
    static void deleteInfoTable(unsigned char*** info);
};

// Represents a move that can be made on a GameState.
struct Move
{
    // Source coordinates
    char source_row;
    char source_col;
    
    // Destination coordinates
    char destination_row;   
    char destination_col;
    
    MoveType type; 
    
    Move(char sr, char sc, char dr, char dc, MoveType t);
    void print() const;
    
    bool operator==(const Move& m) const;
};

std::ostream& operator<<(std::ostream &os, const Move& move); 


// Represents the State of Chess game.
class GameState
{
    public:
        // Board representing the pieces arrangment.
        FieldValue board[8][8];
        
        // Whos turn is next.
        Colour round;
        
        // Stores, data about attacking.
        unsigned int attackInfo[2][8][8];
        
        bool isPlayerUnderCheck;
        bool isEnemyUnderCheck;
        bool isLosingState;
        int drawRuleCount;
        
        // Type definition, for algorithm use
        typedef Move move_type;
        typedef Evaluation value_type;
        
         
        
        // The constructor makes a beginning state. Whites move is next.
        GameState();
        
        // Generate all possible moves for current player.
        std::vector<Move> generateAllMoves() const;
        
        // Generate all possible moves from current GameState.
        std::vector<Move> generateAllSimpleMoves(Colour playerSide, bool generateAlsoAttackMoves) const;
        
        // Generate all possible special moves for current player
        std::vector<Move> generateAllSpecialMoves() const;
        
        // Get a new GameState by applying a move.
        GameState applyMove(const Move& m) const; 
        

        // Check if a move is possible. Will be used for restricting human player moves.
        bool movePossible(const Move &m);
        
        // Hash function
        size_t hash() const;

        bool operator==(const GameState& gs) const 
        {
	       if (round != gs.round) return false;
	       for (int i = 0; i < 8; i++) 
           {
	           for (int j = 0; j < 8; j++) 
               {
	               if (board[i][j] != gs.board[i][j]) return false;
	           }
	       }
	       return true;
        }
        
        // Check if it is a losing state
		  bool computeIsLosingState() const;
		  
        // Just print the GameState
        void print();

    private:
        // Values used for 'special moves'
        bool whiteLeftCastlePossible;
        bool blackLeftCastlePossible;
        bool whiteRightCastlePossible;
        bool blackRightCastlePossible;
        bool lastMoveEnPassantFirstStage;
        short pawnTwoRow;
        short pawnTwoCol;
        
        // Constructor only for internal use of function getState().
        GameState(const FieldValue newBoard[8][8], Colour r);
        
        // Checks if the pair (r,c) is in board range 0 .. 7.
        static bool inBoard(int r, int c);
        
        // Merges two vectors.
        static void merge(std::vector<Move>& base, std::vector<Move>& toMerge);
        
        // Functions used for generating moves.
        std::vector<Move> movePawn(int row, int col, bool generateAlsoAttackMoves) const;
        std::vector<Move> moveKnight(int row, int col, Colour movedPiece) const;
        std::vector<Move> moveBishop(int row, int col, Colour movedPiece) const;
        std::vector<Move> moveRook(int row, int col, Colour movedPiece) const;
        std::vector<Move> moveQueen(int row, int col, Colour movedPiece) const;
        std::vector<Move> moveKing(int row, int col, Colour movedPiece) const;
        
        // All En passant for current colour        
        std::vector<Move> moveEnPassant() const; 
        // All promotion for current colour
        std::vector<Move> movePromotion() const;
        // Casling for current colour
        std::vector<Move> moveCastling() const;
        
        // Generate all posible moves for current player move (white or black).
        std::vector<Move> move(int row, int col, Colour movedPiece, bool generateAlsoAttackMoves) const;
        
        
        // Gets the information about attacked vields in current state
        void getAttackInfo(); 
        
        void computeIsUnderCheck();            
};


namespace std {
    namespace tr1 {
        template<> struct hash<GameState> {
            std::size_t operator()(const GameState& gs) const
            {
                return gs.hash();
            }
        };
    }
}

#endif
